package cn.cloudtogo.adaptation.accesscontrol;

import cn.cloudtogo.authcenter.api.model.access.AccessToken;
import cn.cloudtogo.authcenter.api.model.privilege.PrivilegeResourceDefinition;
import cn.cloudtogo.authcenter.api.model.privilege.ResourceType;
import cn.cloudtogo.authcenter.api.model.staros.StarOSAuthorityParam;
import cn.cloudtogo.authcenter.client.AuthCenterClient;
import cn.cloudtogo.common.atomapi.token.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author yaolianhua789@gmail.com
 **/
@Component
@Slf4j
public class ApiTokenClient implements ApiTokenService {

    private final ApplicationContext applicationContext;
    private final ApiTokenProperties apiTokenProperties;

    public ApiTokenClient(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        apiTokenProperties = applicationContext.getBean(ApiTokenProperties.class);
    }

    private PrivilegeResourceDefinition build(ApiResource apiResource) {
        return PrivilegeResourceDefinition.builder()
                .resourceType(ResourceType.API)
                .apiUrl(apiResource.getPath())
                .method(apiResource.getMethod())
                .build();
    }

    @Override
    public ApiToken obtain(String name, List<ApiResource> apiResources) {
        AuthCenterClient client = applicationContext.getBean(AuthCenterClient.class);

        List<PrivilegeResourceDefinition> definitions = apiResources
                .stream()
                .map(this::build)
                .collect(Collectors.toList());

        try {
            AccessToken accessToken = client.starosAddResources(
                    apiTokenProperties.getAppId(),
                    apiTokenProperties.getGroupId(),
                    definitions
            );
            return ApiToken.of(name, accessToken.getAccessToken(), accessToken.getTokenType(), null);
        } catch (Exception e) {
            log.error("Obtain token error from remote server. {}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public boolean remove(ApiToken apiToken) {
        AuthCenterClient client = applicationContext.getBean(AuthCenterClient.class);

        try {
            client.starosRemoveResources(apiToken.getToken(), apiTokenProperties.getAppId(), apiTokenProperties.getGroupId());
            return true;
        } catch (Exception e) {
            log.error("Remove token error from remote server. {}", e.getMessage(), e);
            return false;
        }

    }

    @Override
    public boolean authenticate(ApiTokenAuthentication authentication) {
        AuthCenterClient client = applicationContext.getBean(AuthCenterClient.class);

        StarOSAuthorityParam authorityParam = StarOSAuthorityParam.builder()
                .apiUrl(authentication.getResource().getPath())
                .method(authentication.getResource().getMethod())
                .build();
        try {
            Boolean authority = client.starosAuthority(
                    authentication.getApiToken().getToken(),
                    apiTokenProperties.getAppId(),
                    apiTokenProperties.getGroupId(),
                    authorityParam
            );
            return authority;
        } catch (Exception e) {
            log.error("Authenticated error from remote server. {}", e.getMessage(), e);
            return false;
        }

    }
}
